package demo6

// 单利模式
// 使用懒惰模式的单例模式，使用双重检查加锁保证线程安全
// 有点像原型设计模式，区别单利可以保证原子性 | 这里的单利引用了内置的sync 包的方法
// sync 里面使用的原子性的操作，判断来初始化变量判断 Singleton | 

import (
	"fmt"
	"sync"
)

type Singleton struct{} // 实例化一次该对象  当然也可以是其他的类型

var one sync.Once
var singleton *Singleton

func GetInstance() *Singleton{
	// Do 传入方法的引用， 内置是实现的该方法， 该方法只会执行一次操作
	one.Do(func(){
		singleton = &Singleton{}
	})
	return singleton
}
// --------------------------------场景2-----------------------------------
// 需求：音乐播放器
// 分析：播放器是一个，音乐 会有很多歌曲，不同的切换歌曲，播放器还是同一个
// 设计，比播放器 vedio  音乐 music  Sing() 歌曲播放

type Vedio struct{}
func (*Vedio)Sing(song string){ fmt.Println("播放歌曲:",song)} // do-something

var vedio *Vedio

func GetVedio() *Vedio{
	one.Do(func(){
		vedio = &Vedio{}
	})
	return vedio
}

// --------------------------------场景3-----------------------------------
// 需求：外键操作另一个表
// 分析：如果使用简单的JDBC的驱动来建立DB连接的话，每一次建立都需要消耗资源，同时开辟内存
// 多次来操作的话，可以考虑单利，同一张表，同一个库，同一个DB。那么就是建立一次连接多次可以使用
// 如果想储存起来连接的话，那么可以通过原型设计模式，存在内存里，类似一个内存池，如果有就直接获取没有的话就创建
// 设计，SqlJDBC 驱动 | 
// 当然简单的方法可以使用一个全局变量也可以实现

type SqlJDBC struct{
	username,passwrod,port,db string 
}

func (s SqlJDBC)Detail(){
	fmt.Println(s.username + " 密码: " + s.passwrod + " 端口: " + s.port," 库: " + s.db)
}
// 这里的声明在这里声明就是方便外部引用
var sqljdbc *SqlJDBC

// 这里要是同一个连接哦，不同的参数肯定占用的空间不一样的，
// 想象一下查询外键表的时候，外键表的参数经过多层for循环 不变的还是这张表
func GetSQLConnection(username,passwrod,port,db string) *SqlJDBC{
	// 提示: DO 内部的方法不支持换行，必须参数func要紧贴着Do
	// 下面用到了闭包，为了方便传入参数来实现的方法否则的话，无法传入参数
	// 如果根据不同的参数来实现的话，这可以加上对应的逻辑判断，比如根据sqljdbc的参数是否相同来做出不同的实例化对象
	// ---------------------------------
	// 原生的单利的缺陷就是，只要实例化 该方法了，那么下次来的时候还是之前的，再传入其他参数，也不会走新的参数来创建了
	// 那么如果需要做出调整的话，要对源码做出整改，但是代价较为昂贵，那么可以考虑更换其他的模式来了，比如原型设计模式
	// 或者其他的方法

	one.Do(func(){
			func(username,passwrod,port,db string){
				// before
				sqljdbc = &SqlJDBC{
					username:username,
					passwrod:passwrod,
					port:port,
					db:db,
				}
			}(username,passwrod,port,db)
		})
	return sqljdbc
}

// --------------------------------场景4-----------------------------------

// 该模式较为简答，但是运用起来的话相对灵活自己可以根据场景来进行拓展
// 拓展方向很多，比如一些多次被创建实例的地方，当然并非这一种模式，能解决方案的方法很多可以根据场景来选择属于自己适合的方法
// 